/*
 * $Id$
 *
 * Copyright (C) Paris8-IUT de Montreuil, 2012-2013
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
package fr.paris8.iut.info.iddl;


import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;
import java.util.Iterator;
import java.util.Vector;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import java.util.AbstractSet;
import java.util.Enumeration;
import java.util.Collections;

//import org.semanticweb.kaon2.api.formatting.OntologyFileFormat;
//import org.semanticweb.owl.align.Alignment;
//import fr.inrialpes.exmo.align.impl.BasicAlignment;
//import org.semanticweb.owl.align.AlignmentProcess;
//import org.semanticweb.owl.align.AlignmentVisitor;
//import org.semanticweb.owl.align.Parameters;

//import fr.inrialpes.exmo.align.impl.BasicParameters;
//import fr.inrialpes.exmo.ontowrap.OntologyCache;
//import fr.inrialpes.exmo.align.parser.AlignmentParser;
//import fr.inrialpes.exmo.align.impl.renderer.HTMLRendererVisitor;
//import fr.inrialpes.exmo.align.impl.renderer.OWLAxiomsRendererVisitor;
//import fr.inrialpes.exmo.align.impl.renderer.RDFRendererVisitor;
//import fr.inrialpes.exmo.align.impl.OWLAPIAlignment;

//import org.mindswap.pellet.owlapi.Reasoner;
//import org.semanticweb.owlapi.reasoner.Reasoner;
import com.clarkparsia.pellet.owlapiv3.PelletReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.BufferingMode;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLClassAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLIndividualAxiom;
import org.semanticweb.owlapi.model.OWLPropertyAxiom;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.util.OWLOntologyChangeVisitorAdapter;
import org.semanticweb.owlapi.model.OWLOntologyID;

import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
import uk.ac.manchester.cs.owl.owlapi.OWLOntologyImpl;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import fr.inrialpes.exmo.ontowrap.OntologyFactory;

public class LocalReasoner {
	public static OWLOntologyManager manager = null;
    	public static PelletReasoner reasoner = null; //JE2010 This should be Reasoner
	public String uriRoot = "http://alignapi.gforge.inria.fr/tutorial/myOnto.owl";
	
	public LocalReasoner() {
		
	    	// Or keep the normal default
	    	//OntologyFactory.setDefaultFactory("fr.inrialpes.exmo.ontowrap.owlapi3.OWLAPI3OntologyFactory");
		manager = OWLManager.createOWLOntologyManager( );
		//reasoner.prepareReasoner();
		//reasoner = new PelletReasoner( manager );//JE2010
	}

    	public void loadOntology( OWLOntology onto ) {
    		reasoner = new PelletReasoner( onto, org.semanticweb.owlapi.reasoner.BufferingMode.NON_BUFFERING);//or BUFFERING ??
		reasoner.prepareReasoner();
    	}
	
    	public void dispose() {
		if ( reasoner != null ) {
		    reasoner.dispose();
		    reasoner = null;
		}
    	}
	
    	public boolean isConsistent(String ontoUri, java.util.Set<OWLAxiom> axioms) {
		boolean response  =  false;
		
		
        
			try
			{
				//System.out.println( "In isConsistent URI="+ ontoUri  );


				OWLOntology onto = manager.loadOntology( IRI.create(ontoUri) );
				 
				//OWLDataFactoryImpl facto = new OWLDataFactoryImpl();

				File tmpOnto = File.createTempFile( "tmpOntology", "owl" );
				OWLOntology onto1 = null;
				try {
					onto1 = manager.createOntology( IRI.create( "file:"+tmpOnto.getAbsolutePath() ) );
				}
				catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }

				//OWLOntologyImpl onto1 = new OWLOntologyImpl( manager, new OWLOntologyID( IRI.create( "file:/tmp/MyOnt.owl" ) ) );
				//JE2010: OWLOntologyImpl onto1 = new OWLOntologyImpl( facto, new OWLOntologyID( IRI.create(ontoUri) ) );
				
				
				
				//System.out.println( "Number of axioms of the initial onto :"+ axiomSet.size() );
				
				//System.out.println( "Number of added axioms : "+ axioms.size() );
				 
				//OWLOntologyChangeVisitorAdapter xc = new OWLOntologyChangeVisitorAdapter();
				Iterator iter= axioms.iterator () ;
				
				while (  iter.hasNext (  )   )  {  
					OWLAxiom ax = (OWLAxiom)iter.next ();
					//System.out.println("Axiom= "+ ax.toString());
					//AddAxiom addaxiom = new AddAxiom(onto, ax);
					AddAxiom addaxiom = new AddAxiom(onto1, ax);
					//addaxiom.accept(xc);
					//onto1.applyChange( addaxiom );
					manager.applyChange(addaxiom);
				}
				
				Set<OWLAxiom> axiomSet = onto.getAxioms();
				iter= axiomSet.iterator () ;
				
				while (  iter.hasNext (  )   )  {  
					OWLAxiom ax = (OWLAxiom)iter.next ();
					//System.out.println("Axiom= "+ ax.toString());
					AddAxiom addaxiom = new AddAxiom(onto1, ax);
					//addaxiom.accept(xc);
					//onto1.applyChange( addaxiom );
					manager.applyChange(addaxiom);
				}

				//manager.saveOntology( onto1 );
				//reasoner = new PelletReasoner( onto1, BufferingMode.NON_BUFFERING);
				//reasoner.prepareReasoner();
				//axiomSet = onto1.getAxioms();
				
				//System.out.println("Number of axioms of the changed ontology : "+ axiomSet.size());
			
				//reasoner.loadOntology( onto1 );//JE??
				loadOntology( onto1 );
			
				//reasoner.getKB().realize();
				//ReasonerManager.reasoner.getKB().printClassTree();
				
				response = reasoner.isConsistent();
				//JE2010: reasoner.unloadOntology( onto1 );
				dispose();
			
        } catch ( Exception ex ) { ex.printStackTrace();}	       
		
		
        return response;
	}
	
	public boolean isConsistent(Vector<URI> ontoUris, OWLOntology alignOnto) {
		boolean response  =  false;
		 
		Set<OWLAxiom> axiomSet = new HashSet();
		if( alignOnto != null ) { 
			axiomSet = alignOnto.getAxioms();
			
		} else {
			//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
			//File tmp = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "" );
			//String aUriStr = "file:"+tmpOnto.getAbsolutePath() + IDDLReasonerImpl.getGlobalOntoName() +".owl";

			String aUriStr = IDDLReasoner.uriRoot + IDDLReasonerImpl.getGlobalOntoName() +".owl";
			IRI aUri = IRI.create(  aUriStr );
			//JE2010: alignOnto =  new OWLOntologyImpl( facto,  new OWLOntologyID( aUri ) );
			//alignOnto =  new OWLOntologyImpl( manager,  new OWLOntologyID( aUri ) );
			try {
				alignOnto = manager.createOntology( aUri );
			}
			catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
		}
		
		//CLD: I do not know why this line is neccessary !
		//reasoner.loadOntology( alignOnto );
		//loadOntology( alignOnto );
		//
		//dispose();//reasoner.unloadOntology( alignOnto );
		
		try {
				
				//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
				//JE2010: OWLOntologyImpl onto1 = new OWLOntologyImpl(facto, 	new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyImpl onto1 = new OWLOntologyImpl(manager, 	new OWLOntologyID( IRI.create( uriRoot )));
				
				File tmpOnto = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "owl" );
				OWLOntology onto1 = null;

				try {
					onto1 = manager.createOntology( IRI.create( "file:"+tmpOnto.getAbsolutePath() ) );
				}
				catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
				//OWLOntologyChangeVisitorAdapter xc = new OWLOntologyChangeVisitorAdapter();
				
				//System.out.println("Number of axioms of align : "+ axiomSet.size());
				
				for (  OWLAxiom ax : axiomSet  )  {  
					
					AddAxiom addaxiom = new AddAxiom(onto1, ax);  
					//addaxiom.accept(xc);
					//onto1.applyChange( addaxiom );
					manager.applyChange(addaxiom);
				}
				
				//reasoner.loadOntology( onto1);
				//System.out.println("onto added by aligns OK");
				
				
				for(int i=0; i < ontoUris.size(); i++) {
					//System.out.println( " uris=" + uris.get(i) );
				    	OWLOntology onto = manager.loadOntology( IRI.create( ontoUris.get(i) ) );
					//OWLOntology onto = ReasonerManager.manager.loadOntology( new URI(uris.get(i)) );
				
					Set<OWLAxiom> axioms = (Set<OWLAxiom>)onto.getAxioms();
					//System.out.println("Number of axioms of onto : "+ axioms.size());
					
					for (  OWLAxiom ax : axioms  )  {  
						AddAxiom addaxiom = new AddAxiom(onto1, ax);  
						//addaxiom.accept(xc);
						manager.applyChange( addaxiom );
					}
					
					//reasoner.loadOntology( onto1 );
					//System.out.println("onto added by "+ ontoUris +"  OK");
					
				}
				
				//java.util.Set<OWLAxiom> axiomSet1 = onto1.getAxioms();
				//System.out.println("Number of axioms of the system : "+ axiomSet1.size());
				//System.out.println("Axioms : "+ axiomSet1.toString());
   		
				//reasoner = new PelletReasoner( onto1, BufferingMode.NON_BUFFERING);
				//reasoner.prepareReasoner();
				loadOntology( onto1 );
				response = reasoner.isConsistent();
				dispose();
				
        } catch ( Exception ex ) { ex.printStackTrace();};
		
        return response;
	}
	
	/* check id each axiom of entailedAlign is entailed from */
	public boolean isEntailed(Vector<URI> ontoUris, OWLOntology alignOnto, OWLOntology entailedAlign) {
		boolean response  =  false;
		  	
		Set<OWLAxiom> axiomSet = new HashSet();
		if( alignOnto != null ) { 
			axiomSet = alignOnto.getAxioms();
			
		} else {
			//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
			//File tmp = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "" );
			String aUriStr = IDDLReasoner.uriRoot + IDDLReasonerImpl.getGlobalOntoName() +".owl";
			//String aUriStr = "file:"+tmpOnto.getAbsolutePath() + IDDLReasonerImpl.getGlobalOntoName() +".owl";
			IRI aUri = IRI.create(  aUriStr );
			//alignOnto =  new OWLOntologyImpl( facto,  new OWLOntologyID( aUri ) );
			//alignOnto =  new OWLOntologyImpl( manager,  new OWLOntologyID( aUri ) );
			try {
				alignOnto = manager.createOntology( aUri );
			}
			catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
		}
		
		//CLD: I do not know why this line is neccessary !
		//reasoner.loadOntology( alignOnto );
		//loadOntology( alignOnto );
		//dispose();//reasoner.unloadOntology( alignOnto );
		
		try {
				
				//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
				//JE2010: OWLOntologyImpl onto1 = new OWLOntologyImpl(facto, 	new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyImpl onto1 = new OWLOntologyImpl( manager, new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyChangeVisitorAdapter xc = new OWLOntologyChangeVisitorAdapter();

				File tmpOnto = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "owl" );
				OWLOntology onto1 = null;
				try {
					onto1 = manager.createOntology( IRI.create( "file:"+tmpOnto.getAbsolutePath() ) );
				}
				catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
				
				//System.out.println("Number of axioms of align : "+ axiomSet.size());
				
				for (  OWLAxiom ax : axiomSet  )  {  
					
					AddAxiom addaxiom = new AddAxiom(onto1, ax);  
					//addaxiom.accept(xc);
					manager.applyChange( addaxiom );
				}
				
				//reasoner.loadOntology( onto1);
				//System.out.println("onto added by aligns OK");
				
				
				for(int i=0; i < ontoUris.size(); i++) {
					//System.out.println( " uris=" + uris.get(i) );
				    OWLOntology onto = manager.loadOntology( IRI.create( ontoUris.get(i) ) );
					//OWLOntology onto = ReasonerManager.manager.loadOntology( new URI(uris.get(i)) );
				
					Set<OWLAxiom> axioms = (Set<OWLAxiom>)onto.getAxioms();
					//System.out.println("Number of axioms of onto : "+ axioms.size());
					
					for (  OWLAxiom ax : axioms  )  {  
						AddAxiom addaxiom = new AddAxiom(onto1, ax);  
						//addaxiom.accept(xc);
						manager.applyChange( addaxiom );
					}
					
					//reasoner.loadOntology( onto1 );
					//System.out.println("onto added by "+ ontoUris +"  OK");
					
				}
				
				//java.util.Set<OWLAxiom> axiomSet1 = onto1.getAxioms();
				//System.out.println("Number of axioms of the system : "+ axiomSet1.size());
				//System.out.println("Axioms : "+ axiomSet1.toString());
   		
				//reasoner.loadOntology( onto1 );
				//loadOntology( onto1 );
				//response = reasoner.isEntailed( entailedAlign.getAxioms() );
				
				/*
				Set<OWLAxiom> entailedAxs = entailedAlign.getAxioms();
				response = true;
				
				for( OWLAxiom ax : entailedAxs) {
				  if ( !(ax instanceof OWLClassAxiom) ) {
					  response = false;
					  break;
				  } else if (!reasoner.isEntailed( ax ) ) { 
					  response = false ;
					  break;
				  }
				}
				*/
				//reasoner.unloadOntology( onto1 );
				//dispose();
				//reasoner = new PelletReasoner( onto1, BufferingMode.NON_BUFFERING);
				//reasoner.prepareReasoner();
				loadOntology( onto1 );
				response = reasoner.isConsistent();
				dispose();
				
        } catch ( Exception ex ) { ex.printStackTrace();};
		
        return response;
	}
	
	public boolean isEntailed(Vector<URI> ontoUris, OWLOntology alignOnto, OWLAxiom cons) {
		boolean response  =  false;
		 
		Set<OWLAxiom> axiomSet = new HashSet();
		if( alignOnto!=null ) { 
			axiomSet = alignOnto.getAxioms();
			
		} else {
			//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
			String aUriStr = IDDLReasoner.uriRoot + IDDLReasonerImpl.getGlobalOntoName() +".owl";
			IRI aUri = IRI.create(  aUriStr );
			//JE2010: alignOnto =  new OWLOntologyImpl( facto,  new OWLOntologyID( aUri ) );
			//alignOnto =  new OWLOntologyImpl( manager,  new OWLOntologyID( aUri ) );
			try {
				alignOnto = manager.createOntology( aUri );
			}
			catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
		}
		
		//CLD: I do not know why this line is neccessary !
		//reasoner.loadOntology( alignOnto );
		//loadOntology( alignOnto );
		//reasoner.unloadOntology( alignOnto );
		//dispose();
		
		try {
				
				//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
				//OWLOntologyImpl onto1 = new OWLOntologyImpl(facto, new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyImpl onto1 = new OWLOntologyImpl(manager, new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyChangeVisitorAdapter xc = new OWLOntologyChangeVisitorAdapter();
				
				File tmpOnto = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "owl" );
				OWLOntology onto1 = null;
				try {
					onto1 = manager.createOntology( IRI.create( "file:"+tmpOnto.getAbsolutePath() ) );

				}
				catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }
				//System.out.println("Number of axioms of align : "+ axiomSet.size());
				
				for (  OWLAxiom ax : axiomSet  )  {  
					
					AddAxiom addaxiom = new AddAxiom(onto1, ax);  
					//addaxiom.accept(xc);
					manager.applyChange( addaxiom );
				}
				
				//reasoner.loadOntology( onto1);
				//System.out.println("onto added by aligns OK");
				
				
				for(int i=0; i < ontoUris.size(); i++) {
					//System.out.println( " uris=" + uris.get(i) );
				    OWLOntology onto = manager.loadOntology( IRI.create( ontoUris.get(i) ) );
					//OWLOntology onto = ReasonerManager.manager.loadOntology( new URI(uris.get(i)) );
				
					Set<OWLAxiom> axioms = (Set<OWLAxiom>)onto.getAxioms();
					//System.out.println("Number of axioms of onto : "+ axioms.size());
					
					for (  OWLAxiom ax : axioms  )  {  
						AddAxiom addaxiom = new AddAxiom(onto1, ax);  
						//addaxiom.accept(xc);
						manager.applyChange( addaxiom );
					}
					
					//reasoner.loadOntology( onto1 );
					//System.out.println("onto added by "+ ontoUris +"  OK");
					
				}
				
				//java.util.Set<OWLAxiom> axiomSet1 = onto1.getAxioms();
				//System.out.println("Number of axioms of the system : "+ axiomSet1.size());
				//System.out.println("Axioms : "+ axiomSet1.toString());
   		
				//reasoner.loadOntology( onto1 );
				loadOntology( onto1 );

				//reasoner.getKB().realize();
				 
				response = reasoner.isEntailed( cons );
				dispose();//reasoner.unloadOntology( onto1 );
				
        } catch ( Exception ex ) { ex.printStackTrace();};
		
        return response;
	}
	
	public boolean isConsistent(Vector<URI> ontoUris, Vector<URI> alignUris) {
		boolean response  =  false;
		String defaultHost = "aserv.inrialpes.fr";
		String defaultPort = "80";
		int idOwl=0;
		  
		
		AlignServer onlineAlign = new AlignServer(defaultPort, defaultHost);
		Set<OWLAxiom> axiomSet = new HashSet<OWLAxiom>();
		OWLOntology ontox = null;
		Set<OWLAxiom> axs =  new HashSet<OWLAxiom>();
		
		for(int i=0; i< alignUris.size(); i++){
			
			String owl = onlineAlign.getOWLAlignment( alignUris.get(i).toString() );
 
			String owlPath =   new Integer(idOwl++) + ".owl";
			try
			{
				File owlFile = new File( owlPath );
			 
				FileWriter out = new FileWriter( owlFile );
			
				out.write( owl );
				out.flush();
				out.close();
				
				ontox = manager.loadOntologyFromOntologyDocument( IRI.create("file:"+owlFile.getAbsolutePath() ));
				axs = ontox.getAxioms();
				
				axiomSet.addAll( axs );
				
				//for (  OWLAxiom ax : axs  ) System.out.println( " axioms from aligns =" + ax.toString() );
				
			} catch ( Exception ex ) { ex.printStackTrace();};
		}
		
		
		try
			{
				
				//OWLDataFactoryImpl facto = new OWLDataFactoryImpl(); 
				//OWLOntologyImpl onto1 = new OWLOntologyImpl(facto, new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyImpl onto1 = new OWLOntologyImpl(manager, new OWLOntologyID( IRI.create( uriRoot )));
				//OWLOntologyChangeVisitorAdapter xc = new OWLOntologyChangeVisitorAdapter();

				File tmpOnto = File.createTempFile( "tmpOntology" + IDDLReasonerImpl.getGlobalOntoName(), "owl" );
				OWLOntology onto1 = null;
				try {
					onto1 = manager.createOntology( IRI.create( "file:"+tmpOnto.getAbsolutePath() ) );
				
				}
				catch (OWLOntologyCreationException ex) { ex.printStackTrace(); }

				for (  OWLAxiom ax : axiomSet  )  {  
					
					AddAxiom addaxiom = new AddAxiom(onto1, ax);  
					//addaxiom.accept(xc);
					manager.applyChange( addaxiom );
				}
				
				for(int i=0; i < ontoUris.size(); i++) {
					//System.out.println( " uris=" + uris.get(i) );
				    OWLOntology onto = manager.loadOntology( IRI.create( ontoUris.get(i) ) );
					//OWLOntology onto = ReasonerManager.manager.loadOntology( new URI(uris.get(i)) );
				
					Set<OWLAxiom> axioms = (Set<OWLAxiom>)onto.getAxioms();
				
					//System.out.println("Number of axioms of the onto "+ i +" : " + axiomSet.size()); 
				
					//Iterator iter= axiomSet.iterator () ;
				
					for (  OWLAxiom ax : axioms  )  {  
						AddAxiom addaxiom = new AddAxiom(onto1, ax);  
						//addaxiom.accept(xc);
						manager.applyChange( addaxiom );
					}
					
				}
				
				//java.util.Set<OWLAxiom> axiomSet1 = onto1.getAxioms();
				//System.out.println("Number of axioms of the system : "+ axiomSet1.size());
			
   		
				//reasoner.loadOntology( onto1 );
				loadOntology( onto1 );
			
				//reasoner.getKB().realize();
				//ReasonerManager.reasoner.getKB().printClassTree();
				
				response = reasoner.isConsistent();
				dispose();//reasoner.unloadOntology( onto1 );
				
			
        } catch ( Exception ex ) { ex.printStackTrace();};
		
        return response;
	}
	
	public boolean checkOnlineConsistency(String ontoUri, java.util.Set<OWLAxiom> axioms){
		
			String answer = null;
			String HOST = null;
			String PORT = null;
			String WSDL = "7777";
			 
			URL SOAPUrl = null;
			String SOAPAction = null;
			 			
			return true;
			
	}
	
	
}
